package eval.engine.cplex.InitialCplexCode;

import eval.engine.cplex.CplexMapIndexToVmId;
import eval.exceptions.CplexMapIndexToVmIdException;
import eval.utilities.configuration.ExperimentConfiguration;
import eval.vm.VMIdentifier;


/**
 * This class hold the data for the CPLEX outside engine.
 * the class hold two components:
 * 		1. placementMap  - int[][]
 * 			this array hold the cloud Structure,
 * 			when the place [i][j] represent: i the VM index and j is the Host index
 * 			only if [i][j]==1 , the VM i deploy at Host j.
 * 		2.  activeHostsMap - int[]
 * 			this array hold the data active host
 * 			when: the place iat the array represent the host id i
 * 			if [i] == 1 the host is open 
 * 			if [i] == 0 the host is close
 * 	
 * 					***********	
 * 		any other values will cause an runtime exception
 * 		We assume that the every input values at this class are valid
 * 					**********
 * 
 * @author Amit Peled   <amit.kapina@gmail.com>
 * @author Igal Kaufman <igal.kaufman@gmail.com> 
 *
 */
public class CplexDataHolder {

	private ExperimentConfiguration conf = ExperimentConfiguration.getSingleton();
	//see description above
	private int[][] placementMap;
	private int[] activeHostsMap;

	/**
	 * @Constructor Copy Constructor Like 
	 * can handle new deploy VM
	 * 
	 * @param prevData CplexDataHolder of last tick
	 * @param curMap current map
	 * @param prevMap map of last tick
	 */
	public CplexDataHolder(CplexDataHolder prevData,
			CplexMapIndexToVmId curMap,CplexMapIndexToVmId prevMap) {
		int[] hostTmp = prevData.getActiveHostsMap();
		this.activeHostsMap = new int[hostTmp.length];
		for(int i=0;i<activeHostsMap.length;i++)
			this.activeHostsMap[i] = hostTmp[i];
		VMIdentifier[] vmTmp = curMap.getCplexIndexToVmId();
		this.placementMap = new int[vmTmp.length][];
		for(int vmIndex = 0;vmIndex<vmTmp.length; vmIndex++) {
			try {
				int prevVmIndex = prevMap.getCplexIndexFromVmId(vmTmp[vmIndex]);
				this.placementMap[vmIndex] = prevData.getPlacementMapOfVm(prevVmIndex);
			} catch (CplexMapIndexToVmIdException e) {//new deploy
				this.placementMap[vmIndex] = new int[hostTmp.length];
			}
		}
	}

	/**
	 * @Constructor Copy Constructor.
	 * 
	 * @param placementMap
	 * @param activeHostsMap
	 */
	public CplexDataHolder (int[][] placementMap,int[] activeHostsMap) {
		if(activeHostsMap==null) {
			this.activeHostsMap = new int[conf.totalNumberOfHosts];
		} else {
			this.activeHostsMap = new int[activeHostsMap.length];
			for(int i= 0; i<activeHostsMap.length;i++)
				this.activeHostsMap[i] = activeHostsMap[i];
		}
		if(placementMap==null) {
			this.placementMap = new int[conf.totalNumberOfHosts][0];
		} else {
			this.placementMap = new int[placementMap.length][];
			for(int i= 0; i<placementMap.length;i++) {
				this.placementMap[i] = new int[placementMap[i].length];
				for(int j=0;j<placementMap[i].length;j++) {
					this.placementMap[i][j] = placementMap[i][j];
				}
			}
		}
	}

	/**
	 * @Constructor Empty Constructor like.
	 * create cloud with no deploy on it
	 * (host will take from configuration file)
	 * all host are closed.
	 * 
	 * @param nbVms number of VM at cloud,
	 */
	public CplexDataHolder(int nbVms) {
		this.placementMap = new int[nbVms][conf.totalNumberOfHosts] ;
		this.activeHostsMap = new int[conf.totalNumberOfHosts];
	}

	/**
	 * @Constructor Empty Constructor like.
	 * create cloud with no deploy on it.
	 * all host are closed
	 * 
	 * @param nbVms number of VM at cloud,
	 * @param nbHosts number of hosts
	 */
	public CplexDataHolder(int nbVms,int nbHosts) {
		this.placementMap = new int[nbVms][nbHosts] ;
		this.activeHostsMap = new int[nbHosts];
	}

	/**
	 * @Constructor Empty Constructor.
	 * create cloud with no deploy on it,
	 * Except the first host all host are closed
	 * (On initial, we force the first host to be active)
	 * 
	 */
	public CplexDataHolder() {
		this.placementMap = new int[0][conf.totalNumberOfHosts] ;
		this.activeHostsMap = new int[conf.totalNumberOfHosts];
		// On initial, we force the first host to be active
		this.activeHostsMap[0] = 1; 
	}
	/**
	 * Get the cloud state.
	 * 
	 * @return the cloud map
	 */
	public int[][] getPlacementMap() {
		return placementMap;
	}

	/**
	 * Get open hosts
	 * 
	 * @return active host map
	 */
	public int[] getActiveHostsMap() {
		return activeHostsMap;
	}

	/**
	 * Get the value of host at active host map
	 * 
	 * @param hostIndex  the host index
	 * @return 1 if is active, 0 otherwise
	 */
	public int getValAtActiveHostMap(int hostIndex){
		return activeHostsMap[hostIndex];
	}

	/**
	 * Get value of placement map
	 * 
	 * @param vmIndex VM index
	 * @param hostIndex host index
	 * @return 1 if VM deploy on host 0 otherwise
	 */
	public int getValAtPlacementMap(int vmIndex,int hostIndex){
		return placementMap[vmIndex][hostIndex];
	}

	/**
	 * Set placement map
	 * 
	 * @param placementMap 
	 */
	public void setPlacementMap(int[][] placementMap) {
		this.placementMap = placementMap;
	}

	/**
	 * Set Active Host map.
	 * 
	 * @param activeHostsMap
	 */
	public void setActiveHostsMap(int[] activeHostsMap) {
		this.activeHostsMap = activeHostsMap;
	}

	/**
	 * Set Active Host map and placement map.
	 * 
	 * @param placementMap
	 * @param activeHostsMap
	 */
	public void setData(int[][] placementMap,int[] activeHostsMap) {
		this.activeHostsMap = activeHostsMap;
		this.placementMap = placementMap;
	}

	/**
	 * Set value at Active Host map
	 * 
	 * @param hostIndex
	 * @param val 
	 */
	public void setValAtActiveHostMap(int hostIndex,int val) {
		activeHostsMap[hostIndex] = val;
	}

	/**
	 * Set value at placement map
	 * 
	 * @param vmIndex
	 * @param hostIndex
	 * @param val
	 */
	public void setValAtPlacementMap(int vmIndex,int hostIndex,int val) {
		placementMap[vmIndex][hostIndex] = val;
	}

	/**
	 * Get placement map of VM  
	 * 
	 * @param vmIndex the VM
	 * @return the placement map of this VM
	 */
	public int[] getPlacementMapOfVm(int vmIndex) {
		return placementMap[vmIndex];
	}
}
